package controllers

import (
	"encoding/json"
	"os/exec"

	"gitee.com/hailaz/wakeonlan/models"

	"fmt"
	"net/http"
	"time"

	"github.com/astaxie/beego"
	"github.com/gorilla/websocket"
)

type WebsocketController struct {
	beego.Controller
}

const (
	codeSave      int = 200  //保存设备
	codeLogout    int = 100  //退出
	codeLogin     int = 101  //登陆
	codeSetPC     int = 102  //设置电脑
	codeWol       int = 666  //唤醒
	codeExist     int = 998  //不可重复登录
	codeError     int = 999  //错误
	codeHeartbeat int = 1000 //心跳
	typeClient    int = 1    //客户端
	typeControl   int = 2    //控制端
)

type PC struct {
	Mac    string `json:"mac"`
	Name   string `json:"name"`
	IP     string `json:"ip"`
	Status int    `json:"status"`
}

type WsMessage struct {
	Name         string `json:"name"`
	Code         int    `json:"code"`
	Type         int    `json:"type"`
	ClientStatus int    `json:"clientstatus"`
	PC           []PC   `json:"pc"`
	Data         string `json:"data"`
}

type client struct {
	ws       *websocket.Conn
	Name     string
	LastDate time.Time
}

var WolClients map[string]*client

var WolControls map[string]*client

func init() {
	WolClients = make(map[string]*client)
	WolControls = make(map[string]*client)
}

func (c *WebsocketController) Ud() {
	go exec.Command("cmd.exe", "/c", "start "+"wakeonlan.bat").Output()
	c.Redirect("/", 302)
}

// websocket主入口
func (c *WebsocketController) Websocket() {
	c.TplName = "wol/index.html"
	// 将Restful连接升级为websocket
	//c.Ctx.ResponseWriter.Header().Set("Access-Control-Allow-Origin", "*")
	u := websocket.Upgrader{
		CheckOrigin: func(r *http.Request) bool {
			return true
		},
	}

	ws, err := u.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
	//fmt.Println("con:", ws.RemoteAddr().String())
	if err != nil {
		fmt.Println(err) //这里panic抛出错误，
	} else {
		// 必须为死循环，不断监听
		for {
			// 接收数据
			_, p, err := ws.ReadMessage()
			if err != nil {
				for _, v := range WolClients {
					if v.ws.RemoteAddr().String() == ws.RemoteAddr().String() {
						delete(WolClients, v.Name)
						beego.Debug("app意外退出:", v.Name)
						//fmt.Println("close:", v.Name, v.ws.RemoteAddr().String())
					}
				}
				return
			} else {
				// 接收回来的数据转化为json

				msg := StrToMsg(string(p))
				name := msg.Name
				//fmt.Println(msg)

				switch msg.Type {
				case typeClient:
					wc, ok := WolClients[name]
					if ok {
						wc.LastDate = time.Now()
					}
					switch msg.Code {
					case codeHeartbeat:
						//fmt.Println("心跳：" + name)
					case codeLogout:
						if ok {
							delete(WolClients, name)
							beego.Debug("app退出:", name)
						}
					case codeLogin:
						if ok {
							if wc.ws.RemoteAddr().String() != ws.RemoteAddr().String() {
								m := WsMessage{Code: codeExist, Data: "用户已在其他app登录，不可重复登录"}
								ws.WriteMessage(websocket.TextMessage, []byte(MsgToStr(m)))
								break
							}
						} else {
							c := client{
								ws:   ws,
								Name: name,
							}
							WolClients[name] = &c
							beego.Debug("app登录:", name)
						}
						wol := ReadWol(name)
						ws.WriteMessage(websocket.TextMessage, []byte(wol.Data))
					case codeSave:
						SaveWol(msg)
					}
				case typeControl:
					switch msg.Code {
					case codeHeartbeat:
						//fmt.Println("心跳：" + name)
					case codeLogin:
						/*
							c := client{
								ws:   ws,
								Name: name,
							}
							WolControls[name] = c
						*/
						wol := ReadWol(name)
						msg := StrToMsg(wol.Data)
						_, ok := WolClients[name]
						if ok {
							msg.ClientStatus = 1
						} else {
							msg.ClientStatus = 0
						}
						ws.WriteMessage(websocket.TextMessage, []byte(MsgToStr(*msg)))
					case codeWol:
						wc, ok := WolClients[name]
						if ok {
							wc.ws.WriteMessage(websocket.TextMessage, p)
							m := WsMessage{Code: codeError, Data: "唤醒命令已发送"}
							ws.WriteMessage(websocket.TextMessage, []byte(MsgToStr(m)))
						} else {
							m := WsMessage{Code: codeError, Data: "远端APP不在线"}
							ws.WriteMessage(websocket.TextMessage, []byte(MsgToStr(m)))
						}

					}
				}
				//fmt.Println(WolClients)
				//fmt.Println(WolControls)
			}

		}
	}
}

func ReadWol(name string) *models.WakeOnLan {
	wol := models.GetWakeOnlanByName(name)
	//beego.Debug(wol.Data)
	if wol.Data == "" {
		m := WsMessage{Name: name, PC: []PC{}}
		SaveWol(&m)
		wol = models.GetWakeOnlanByName(name)
	}
	return wol
}

func SaveWol(msg *WsMessage) {
	msg.Code = codeSetPC
	wol := models.GetWakeOnlanByName(msg.Name)
	wol.Data = MsgToStr(*msg)
	wol.Update()
}

func MsgToStr(msg WsMessage) string {
	b, _ := json.Marshal(msg)
	return string(b)
}

func StrToMsg(str string) *WsMessage {
	msg := new(WsMessage)
	json.Unmarshal([]byte(str), msg)
	return msg
}

func (c *WebsocketController) Wol() {
	c.Data["title"] = "wol"
	c.TplName = "wol/index.html"
}

func (c *WebsocketController) Wols() {
	c.Data["list"] = WolClients
	c.TplName = "wol/wols.html"
}
